/*
** Copyright (C) 2010 Calin Radoni
**
** This file is part of CHScanner.
**
** CHScanner is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** CHScanner is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with CHScanner. If not, see <http://www.gnu.org/licenses/>.
*/

// DlgDetails.cpp : implementation file

#include "stdafx.h"
#include "CHScanner.h"
#include "DlgDetails.h"
#include ".\dlgdetails.h"

//---------------------------------------------------------------------------

IMPLEMENT_DYNAMIC(DlgDetails, CRgnDialog)
DlgDetails::DlgDetails(CWnd* pParent /*=NULL*/) : CRgnDialog(DlgDetails::IDD, pParent)
{
	vendorList   = NULL;
	mcast4List   = NULL;
	portDescList = NULL;
}

DlgDetails::~DlgDetails()
{
}

//---------------------------------------------------------------------------

void DlgDetails::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_TREE_DETAILS, theTree);
}


//---------------------------------------------------------------------------

BEGIN_MESSAGE_MAP(DlgDetails, CRgnDialog)
END_MESSAGE_MAP()

//---------------------------------------------------------------------------

BOOL DlgDetails::OnInitDialog()
{
	CRgnDialog::OnInitDialog();

	// TODO:  Add extra initialization here

	return TRUE;  // return TRUE unless you set the focus to a control
	// EXCEPTION: OCX Property Pages should return FALSE
}

//---------------------------------------------------------------------------

void DlgDetails::ResizeChilds(void)
{
	theTree.MoveWindow(clientRect.left, clientRect.top, clientRect.right - clientRect.left, clientRect.bottom - clientRect.top, TRUE);
}

//---------------------------------------------------------------------------

CString DlgDetails::DwTimeToDHMS(DWORD dwIn)
{
	CString str, sss;
	DWORD rem;
	int dd, hh, mm, ss;

	rem = dwIn;
	dd = 0;
	hh = 0;
	mm = 0;
	ss = 0;
	str.Empty();

	while(rem>=86400){
		dd++;
		rem -= 86400;
	}
	switch(dd){
		case 0:
			str.Empty();
			break;
		case 1:
			str = "1 day";
			break;
		default:
			str.Format(_T("%d days"), dd);
			break;
	}
	if(rem==0) return str;
	
	if(dd!=0) str += " ";

	while(rem>=3600){
		hh++;
		rem -=3600;
	}
	switch(hh){
		case 0:
			break;
		case 1:
			str += "1 hour";
			break;
		default:
			sss.Format(_T("%d hours"), hh);
			str += sss;
			break;
	}
	if(rem==0) return str;

	if(hh!=0) str += " ";

	while(rem>=60){
		mm++;
		rem -=60;
	}
	switch(mm){
		case 0:
			break;
		case 1:
			str += "1 minute";
			break;
		default:
			sss.Format(_T("%d minutes"), mm);
			str += sss;
			break;
	}
	if(rem==0) return str;

	if(mm!=0) str += " ";

	ss = rem;
	switch(ss){
		case 0:
			break;
		case 1:
			str += "1 second";
			break;
		default:
			sss.Format(_T("%d seconds"), ss);
			str += sss;
			break;
	}

	return str;
}

//---------------------------------------------------------------------------

CString DlgDetails::DwToIpStr(DWORD dwIn)
{
	CString str;
	in_addr ia;

	ia.S_un.S_addr = dwIn;
	str = inet_ntoa(ia);
	return str;
}

//---------------------------------------------------------------------------

CString DlgDetails::GetMethodName(WorkMethodType wmtIn)
{
	return wd.GetMethodName(wmtIn);
}

//---------------------------------------------------------------------------

bool DlgDetails::AddPortsForMethod(MMachineInfo* mmi, HTREEITEM parentItem, WorkMethodType wmtIn, bool expand)
{
	HTREEITEM item;
	HTREEITEM itmp;
	MPortInfo* mpi;
	CString str, portDescStr;
	int i, cnt;
	bool respReceived;

	if(mmi==NULL) return true;

	item = NULL;

	if(wmtIn==__wmtIpProtocol || wmtIn==__wmt6Proto) cnt = mmi->GetProtoCount();
	else                                             cnt = mmi->GetPortCount();

	for(i=0; i<cnt; i++){
		if(wmtIn==__wmtIpProtocol || wmtIn==__wmt6Proto) mpi = mmi->GetProtoInfo(i);
		else                                             mpi = mmi->GetPortInfo(i);

		if(mpi!=NULL){
			if(mpi->method==wmtIn){
				// found one

				if(item==NULL){
					// it is the first one so create parent

					str.Format(_T("%s results"), GetMethodName(wmtIn));
					switch(wmtIn){
						case __wmtFin :
							respReceived = mmi->recvFin;
							break;

						case __wmtNull :
							respReceived = mmi->recvNull;
							break;

						case __wmtXmas :
							respReceived = mmi->recvXmas;
							break;

						case __wmtUdpSend :
							respReceived = mmi->recvUdpSend;
							break;

						case __wmt6Fin :
							respReceived = mmi->recv6Fin;
							break;

						case __wmt6Null :
							respReceived = mmi->recv6Null;
							break;

						case __wmt6Xmas :
							respReceived = mmi->recv6Xmas;
							break;

						case __wmt6UdpSend :
							respReceived = mmi->recv6UdpSend;
							break;

						case __wmtIpProtocol :
							respReceived = mmi->recvIpProto;
							break;

						case __wmt6Proto :
							respReceived = mmi->recv6NextHeader;
							break;

						default:
							respReceived = false;
							break;
					}
					switch(wmtIn){
						case __wmtSyn :
						case __wmt6Syn :
						case __wmtAck :
						case __wmt6Ack :

						case __wmtHunt :

						case __wmtPassiveTCP :
						case __wmtPassiveUDP :
						case __wmtPassiveTCPv6 :
						case __wmtPassiveUDPv6 :
							break;

						default:
							if(!respReceived)
								str += _T(" (Warning: no response received from host!)");
							break;
					}

					item = theTree.InsertItem(str, parentItem, TVI_LAST);
					if(item==NULL) return false;
				}

				if(portDescList==NULL) portDescStr.Empty();
				else{
					switch(wmtIn){
						case __wmtIpProtocol :
						case __wmt6Proto :
							portDescStr = portDescList->GetPortDescription(__mpdpProtocol, mpi->port);
							break;

						case __wmtUdpSend :
						case __wmt6UdpSend :
							portDescStr = portDescList->GetPortDescription(__mpdpUdp, mpi->port);
							break;

						default :
							portDescStr = portDescList->GetPortDescription(__mpdpTcp, mpi->port);
							break;
					}
				}

				if(mpi->method==__wmtSyn || mpi->method==__wmt6Syn){
					if(mpi->timeInterval==0) str.Format(_T("%d (%s), time <1 ms"), mpi->port, portDescStr);
					else                     str.Format(_T("%d (%s), time %d ms"), mpi->port, portDescStr, mpi->timeInterval);
				}
				else                         str.Format(_T("%d (%s)"), mpi->port, portDescStr);
				itmp = theTree.InsertItem(str, item, TVI_LAST);
				if(itmp==NULL) return false;
			}
		}
	}


	if(expand && item!=NULL)
		theTree.Expand(item, TVE_EXPAND);

	return true;
}

//---------------------------------------------------------------------------

bool DlgDetails::AddInfoMAC(MMachineInfo* mmi, HTREEITEM parentItem)
{
	HTREEITEM item;
	CString str;
	CString sss;

	if(!mmi->address.gwMAC){
		str.Format(_T("MAC Address is %s"), mmi->address.addrMAC.GetS());
		if(vendorList!=NULL){
			sss = vendorList->GetVendorName(&mmi->address.addrMAC);
			if(!sss.IsEmpty()){
				str += _T(" (");
				str += sss;
				str += _T(")");
			}
		}
		item = theTree.InsertItem(str, parentItem, TVI_LAST);
		if(item==NULL) return false;
	}

	if(!mmi->address.addrMACnb.IsEmpty()){
		str.Format(_T("MAC Address is %s, by NetBios"), mmi->address.addrMACnb.GetS());
		if(vendorList!=NULL){
			sss = vendorList->GetVendorName(&mmi->address.addrMACnb);
			if(!sss.IsEmpty()){
				str += _T(" (");
				str += sss;
				str += _T(")");
			}
		}
		item = theTree.InsertItem(str, parentItem, TVI_LAST);
		if(item==NULL) return false;
	}

	return true;
}

//---------------------------------------------------------------------------

bool DlgDetails::AddNetBiosNames(MMachineInfo* mmi, HTREEITEM parentItem, bool expand)
{
	HTREEITEM item;
	HTREEITEM cItem;
	CString str;
	int i;

	if(mmi==NULL)         return false;
	if(mmi->nbNamesCnt<0) return false;

	if(mmi->nbNamesCnt==0)   return true;

	str = _T("NetBios Names");
	item = theTree.InsertItem(str, parentItem, TVI_LAST);
	if(item==NULL) return false;

	for(i=0; i<mmi->nbNamesCnt; i++){
		cItem = theTree.InsertItem(mmi->nbNames[i], item, TVI_LAST);
		if(cItem==NULL) return false;
	}

	if(expand && item!=NULL)
		theTree.Expand(item, TVE_EXPAND);

	return true;
}

//---------------------------------------------------------------------------

bool DlgDetails::AddSharesInfo(MMachineInfo* mmi, HTREEITEM parentItem, bool expand)
{
	HTREEITEM item;
	HTREEITEM cItem;
	CString str;
	int i, cnt;
	MShareInfo *shareInfo;

	if(mmi==NULL) return false;

	cnt = mmi->GetShareInfoCount();
	if(cnt<0) return false;
	if(cnt==0) return true;

	mmi->SortShareInfo();

	str.Format(_T("Shares (%d)"), cnt);
	item = theTree.InsertItem(str, parentItem, TVI_LAST);
	if(item==NULL) return false;

	for(i=0; i<cnt; i++){
		shareInfo = mmi->GetShareInfo(i);
		if(shareInfo!=NULL){
			if(shareInfo->remark.GetLength()>0) str.Format("%s - %s", shareInfo->name, wd.GetShareTypeName(shareInfo->type));
			else                                str.Format("%s - %s (%s)", shareInfo->name, wd.GetShareTypeName(shareInfo->type), shareInfo->remark);
			cItem = theTree.InsertItem(str, item, TVI_LAST);
			if(cItem==NULL) return false;
		}
	}

	if(expand && item!=NULL)
		theTree.Expand(item, TVE_EXPAND);

	return true;
}

//---------------------------------------------------------------------------

bool DlgDetails::AddSnmpSysInfo(MMachineInfo* mmi, HTREEITEM parentItem, bool expand)
{
	HTREEITEM item;
	HTREEITEM cItem;
	CString str;

	if(mmi==NULL) return false;

	if(mmi->snmpSysRec.IsEmpty()) return true;

	str = _T("SNMP System Informations");
	item = theTree.InsertItem(str, parentItem, TVI_LAST);
	if(item==NULL) return false;
	
	if(!mmi->snmpSysRec.sysDescription.IsEmpty()){
		str.Format(_T("Description: %s"), mmi->snmpSysRec.sysDescription);
		cItem = theTree.InsertItem(str, item, TVI_LAST);
		if(cItem==NULL) return false;
	}

	if(!mmi->snmpSysRec.sysVendorOid.IsEmpty()){
		str.Format(_T("Vendor OID: %s"), mmi->snmpSysRec.sysVendorOid);
		cItem = theTree.InsertItem(str, item, TVI_LAST);
		if(cItem==NULL) return false;
	}

	if(!mmi->snmpSysRec.sysContact.IsEmpty()){
		str.Format(_T("Contact: %s"), mmi->snmpSysRec.sysContact);
		cItem = theTree.InsertItem(str, item, TVI_LAST);
		if(cItem==NULL) return false;
	}

	if(!mmi->snmpSysRec.sysName.IsEmpty()){
		str.Format(_T("Name: %s"), mmi->snmpSysRec.sysName);
		cItem = theTree.InsertItem(str, item, TVI_LAST);
		if(cItem==NULL) return false;
	}

	if(!mmi->snmpSysRec.sysLocation.IsEmpty()){
		str.Format(_T("Location: %s"), mmi->snmpSysRec.sysLocation);
		cItem = theTree.InsertItem(str, item, TVI_LAST);
		if(cItem==NULL) return false;
	}

	if(mmi->snmpSysRec.sysUpTime>0){
		str.Format(_T("Up time: %s"), DwTimeToDHMS(mmi->snmpSysRec.sysUpTime/100));
		cItem = theTree.InsertItem(str, item, TVI_LAST);
		if(cItem==NULL) return false;
	}

	if(mmi->snmpSysRec.sysServices!=0){
		str = _T("Services: ");
		if(mmi->snmpSysRec.sysServices & 0x01) str += _T("1 ");
		if(mmi->snmpSysRec.sysServices & 0x02) str += _T("2 ");
		if(mmi->snmpSysRec.sysServices & 0x04) str += _T("3 ");
		if(mmi->snmpSysRec.sysServices & 0x08) str += _T("4 ");
		if(mmi->snmpSysRec.sysServices & 0x10) str += _T("5 ");
		if(mmi->snmpSysRec.sysServices & 0x20) str += _T("6 ");
		if(mmi->snmpSysRec.sysServices & 0x40) str += _T("7 ");
		str.Trim();
		cItem = theTree.InsertItem(str, item, TVI_LAST);
		if(cItem==NULL) return false;
	}

	if(expand && item!=NULL)
		theTree.Expand(item, TVE_EXPAND);

	return true;
}

//---------------------------------------------------------------------------

bool DlgDetails::AddInfoDHCP(MMachineInfo* mmi, HTREEITEM parentItem, bool expand)
{
	HTREEITEM item;
	HTREEITEM cItem;
	HTREEITEM oItem;
	CString str;
	int i, cnt;
	MDHCPOption* opt;

	if(mmi==NULL) return false;

	if(mmi->infoDHCP.isEmpty) return true;

	str = _T("DHCP Informations");
	item = theTree.InsertItem(str, parentItem, TVI_LAST);
	if(item==NULL) return false;

	if(mmi->infoDHCP.yiAddr!=0){
		str.Format(_T("Offered IP address is %s"), DwToIpStr(mmi->infoDHCP.yiAddr));
		cItem = theTree.InsertItem(str, item, TVI_LAST);
		if(cItem==NULL) return false;
	}

	if(mmi->infoDHCP.hLen!=0){
		str.Format(_T("Client hardware address is %s"), infoDescDHCP.DhcpMacToStr(mmi->infoDHCP.chAddr, mmi->infoDHCP.hLen));
		cItem = theTree.InsertItem(str, item, TVI_LAST);
		if(cItem==NULL) return false;
	}

	if(mmi->infoDHCP.siAddr!=0){
		str.Format(_T("Server identifier is %s"), DwToIpStr(mmi->infoDHCP.siAddr));
		cItem = theTree.InsertItem(str, item, TVI_LAST);
		if(cItem==NULL) return false;
	}

	if(mmi->infoDHCP.giAddr!=0){
		str.Format(_T("Relay agent IP address is %s"), DwToIpStr(mmi->infoDHCP.giAddr));
		cItem = theTree.InsertItem(str, item, TVI_LAST);
		if(cItem==NULL) return false;
	}

	cnt = mmi->infoDHCP.optList.GetSize();
	if(cnt>0){
		str = _T("Options");
		cItem = theTree.InsertItem(str, item, TVI_LAST);
		if(cItem==NULL) return false;

		for(i=0; i<cnt; i++){
			opt = mmi->infoDHCP.optList.GetByIdx(i);
			if(opt!=NULL){
				str = infoDescDHCP.FormatDhcpOptionAsString(opt, true);
				oItem = theTree.InsertItem(str, cItem, TVI_LAST);
				if(oItem==NULL) return false;
			}
		}
	}

	if(expand && item!=NULL)
		theTree.Expand(item, TVE_EXPAND);

	if(expand && cItem!=NULL)
		theTree.Expand(item, TVE_EXPAND);

	return true;
}

//---------------------------------------------------------------------------

bool DlgDetails::AddPromiscResults(MMachineInfo* mmi, HTREEITEM parentItem, bool expand)
{
	HTREEITEM item;
	HTREEITEM cItem;
	CString str;

	if(mmi==NULL) return false;

	if(mmi->address.promiscState==0) return true;

	str = _T("Promiscuous Node Scan");
	item = theTree.InsertItem(str, parentItem, TVI_LAST);
	if(item==NULL) return false;

	if(mmi->address.promiscState & 0x01){
		str = _T("Broadcast 47 received");
		cItem = theTree.InsertItem(str, item, TVI_LAST);
		if(cItem==NULL) return false;
	}

	if(mmi->address.promiscState & 0x02){
		str = _T("Broadcast 16 received");
		cItem = theTree.InsertItem(str, item, TVI_LAST);
		if(cItem==NULL) return false;
	}

	if(mmi->address.promiscState & 0x04){
		str = _T("Broadcast 8 received");
		cItem = theTree.InsertItem(str, item, TVI_LAST);
		if(cItem==NULL) return false;
	}

	if(mmi->address.promiscState & 0x08){
		str = _T("Group bit received");
		cItem = theTree.InsertItem(str, item, TVI_LAST);
		if(cItem==NULL) return false;
	}

	if(mmi->address.promiscState & 0x10){
		str = _T("Multicast address 0 received");
		cItem = theTree.InsertItem(str, item, TVI_LAST);
		if(cItem==NULL) return false;
	}

	if(mmi->address.promiscState & 0x20){
		str = _T("Multicast address 1 received");
		cItem = theTree.InsertItem(str, item, TVI_LAST);
		if(cItem==NULL) return false;
	}

	if(expand && item!=NULL)
		theTree.Expand(item, TVE_EXPAND);

	return true;
}

//---------------------------------------------------------------------------

bool DlgDetails::AddIgmpInfo(MMachineInfo* mmi, HTREEITEM parentItem, bool expand)
{
	HTREEITEM item;
	HTREEITEM cItem;
	CString str, mcast4Name;
	int i, cnt;
	MIGMPPacket *mpg;
	bool err;

	if(mmi==NULL) return false;

	cnt = mmi->GetIgmpPackCount();
	if(cnt==0) return true;

	str = _T("IGMP Informations");
	item = theTree.InsertItem(str, parentItem, TVI_LAST);
	if(item==NULL) return false;

	err = false;
	for(i=0; i<cnt && !err; i++){
		mpg = mmi->GetIgmpPack(i);
		if(mpg!=NULL){
			mcast4Name.Empty();
			if(mpg->addr.GetD()!=0) 
				if(mcast4List!=NULL)
					mcast4Name = mcast4List->GetName(mpg->addr.GetD(), true);

			if(mcast4Name.IsEmpty()){
				if(mpg->recordType!=0) str.Format(_T("%s - %s, %s"), mpg->addr.GetS(), mpg->GetTypeName(), mpg->GetRecordTypeName());
				else                   str.Format(_T("%s - %s"),     mpg->addr.GetS(), mpg->GetTypeName());
			}
			else{
				if(mpg->recordType!=0) str.Format(_T("%s (%s) - %s, %s"), mpg->addr.GetS(), mcast4Name, mpg->GetTypeName(), mpg->GetRecordTypeName());
				else                   str.Format(_T("%s (%s) - %s"),     mpg->addr.GetS(), mcast4Name, mpg->GetTypeName());
			}

			cItem = theTree.InsertItem(str, item, TVI_LAST);
			if(cItem==NULL) err = true;
		}
	}

	if(expand && item!=NULL)
		theTree.Expand(item, TVE_EXPAND);

	return !err;
}

//---------------------------------------------------------------------------

bool DlgDetails::AddGxRPInfo(MMachineInfo* mmi, HTREEITEM parentItem, bool expand)
{
	HTREEITEM   item;
	CString     str;
	int         i, cnt;
	MGxRPPacket *mpgx;
	bool        err;

	if(mmi==NULL) return false;
	cnt = mmi->GetGxRPPackCount();
	if(cnt==0) return true;

	str = _T("GARP");
	item = theTree.InsertItem(str, parentItem, TVI_LAST);
	if(item==NULL) return false;

	err = false;
	for(i=0; i<cnt; i++){
		mpgx = mmi->GetGxRPPack(i);
		if(mpgx!=NULL)
			if(!AddGxRPPacket(mpgx, item, expand))
				err = true;
	}

	if(expand)
		theTree.Expand(item, TVE_EXPAND);

	return !err;
}

bool DlgDetails::AddGxRPPacket(MGxRPPacket* packIn, HTREEITEM parentItem, bool expand)
{
	HTREEITEM   item, cItem;
	CString     str;
	int         i, cnt;
	MLEVRecord *rec;
	bool        err;

	if(packIn==NULL) return true;

	str.Format(_T("%s, %s"), mGxRPDecoder.GetProtocolName(packIn), mGxRPDecoder.GetAttributeTypeName(packIn));
	item = theTree.InsertItem(str, parentItem, TVI_LAST);
	if(item==NULL) return false;

	cnt = packIn->Attributes.GetSize();
	if(cnt==0) return true;

	err = false;
	for(i=0; i<cnt && !err; i++){
		rec = packIn->Attributes.GetByIdx(i);
		if(rec!=NULL){
			str.Format(_T("%s, %s"),
				mGxRPDecoder.GetAttributeEventName(rec->xEvent),
				mGxRPDecoder.GetAttributeValue(packIn, rec->xLength, rec->xValue[0], rec->xValue[1]));
			cItem = theTree.InsertItem(str, item, TVI_LAST);
			if(cItem==NULL) err = true;
		}
	}

	return !err;
}

//---------------------------------------------------------------------------

bool DlgDetails::AddCDPInfo(MMachineInfo* mmi, HTREEITEM parentItem, bool expand)
{
	HTREEITEM   item;
	CString     str;
	int         i, cnt;
	MCDPPacket  *cdpx;
	bool        err;

	if(mmi==NULL) return false;
	cnt = mmi->GetCDPPackCount();
	if(cnt==0) return true;

	str = _T("CDP");
	item = theTree.InsertItem(str, parentItem, TVI_LAST);
	if(item==NULL) return false;

	err = false;
	for(i=0; i<cnt; i++){
		cdpx = mmi->GetCDPPack(i);
		if(cdpx!=NULL)
			if(!AddCDPPacket(cdpx, item, expand))
				err = true;
	}

	if(expand)
		theTree.Expand(item, TVE_EXPAND);

	return !err;
}

bool DlgDetails::AddCDPPacket(MCDPPacket* packIn, HTREEITEM parentItem, bool expand)
{
	HTREEITEM   item, cItem;
	CString     str;
	int         i, cnt;
	MTLVRecord *rec;
	bool        err;

	if(packIn==NULL) return true;

	// deviceID, portID, platform
	str.Format(_T("Device %s, port %s, platform %s"),
		mCDPDecoder.FindAndGetTypeValueAsString(packIn, CDPT_DeviceId),
		mCDPDecoder.FindAndGetTypeValueAsString(packIn, CDPT_PortId),
		mCDPDecoder.FindAndGetTypeValueAsString(packIn, CDPT_Platform));
	item = theTree.InsertItem(str, parentItem, TVI_LAST);
	if(item==NULL) return false;

	cnt = packIn->xValuesList.GetSize();
	if(cnt==0) return true;

	err = false;
	for(i=0; i<cnt && !err; i++){
		rec = packIn->xValuesList.GetByIdx(i);
		if(rec!=NULL){
			str.Format(_T("%s: %s"), mCDPDecoder.GetTypeName(rec->xType), mCDPDecoder.GetValueName(rec));
			cItem = theTree.InsertItem(str, item, TVI_LAST);
			if(cItem==NULL) err = true;
		}
	}

	return !err;
}

//---------------------------------------------------------------------------

bool DlgDetails::AddSTPInfo(MMachineInfo* mmi, HTREEITEM parentItem, bool expand)
{
	HTREEITEM   item, cItem, aItem;
	CString     str;
	int         i, cnt;
	MSTPPacket  *stpx;
	MAddressMAC macAddr;

	if(mmi==NULL) return false;
	cnt = mmi->GetSTPPackCount();
	if(cnt==0) return true;

	str = _T("STP");
	item = theTree.InsertItem(str, parentItem, TVI_LAST);
	if(item==NULL) return false;

	for(i=0; i<cnt; i++){
		stpx = mmi->GetSTPPack(i);
		if(stpx!=NULL){
			if(!stpx->IsEmpty()){
				macAddr.LoadFromBytePtr(&(stpx->BridgeIdMAC[0]));
				str.Format(_T("Bridge ID is %s, priority %s"), macAddr.GetS(), mSTPDecoder.FormatPriorityRaw(stpx->BridgeIdPriority));
				cItem = theTree.InsertItem(str, item, TVI_LAST);
				if(cItem==NULL) return false;

				str.Format(_T("Protocol ID: %u"), stpx->ProtocolId);
				aItem = theTree.InsertItem(str, cItem, TVI_LAST);
				if(aItem==NULL) return false;

				str.Format(_T("Version: %u"), stpx->Version);
				aItem = theTree.InsertItem(str, cItem, TVI_LAST);
				if(aItem==NULL) return false;

				str.Format(_T("Message Type: %s"), mSTPDecoder.GetMessageTypeName(stpx));
				aItem = theTree.InsertItem(str, cItem, TVI_LAST);
				if(aItem==NULL) return false;

				str.Format(_T("Flags: %s"), mSTPDecoder.GetFlagsName(stpx));
				aItem = theTree.InsertItem(str, cItem, TVI_LAST);
				if(aItem==NULL) return false;

				macAddr.LoadFromBytePtr(&(stpx->RootIdMAC[0]));
				str.Format(_T("Root ID is %s, priority %s (%s)"),
					macAddr.GetS(),
					mSTPDecoder.FormatPriorityRaw(stpx->RootIdPriority),
					mSTPDecoder.FormatPriorityAsCisco(stpx->RootIdPriority));
				aItem = theTree.InsertItem(str, cItem, TVI_LAST);
				if(aItem==NULL) return false;

				str.Format(_T("Root Path Cost: %u"), stpx->RootPathCost);
				aItem = theTree.InsertItem(str, cItem, TVI_LAST);
				if(aItem==NULL) return false;

				macAddr.LoadFromBytePtr(&(stpx->BridgeIdMAC[0]));
				str.Format(_T("Bridge ID is %s, priority %s (%s)"),
					macAddr.GetS(),
					mSTPDecoder.FormatPriorityRaw(stpx->BridgeIdPriority),
					mSTPDecoder.FormatPriorityAsCisco(stpx->BridgeIdPriority));
				aItem = theTree.InsertItem(str, cItem, TVI_LAST);
				if(aItem==NULL) return false;

				str.Format(_T("Port Id: 0x%x"), stpx->PortId);
				aItem = theTree.InsertItem(str, cItem, TVI_LAST);
				if(aItem==NULL) return false;

				str.Format(_T("Message Age[s]: %u"), stpx->MessageAge>>8);
				aItem = theTree.InsertItem(str, cItem, TVI_LAST);
				if(aItem==NULL) return false;

				str.Format(_T("Maximum Age[s]: %u"), stpx->MaximumAge>>8);
				aItem = theTree.InsertItem(str, cItem, TVI_LAST);
				if(aItem==NULL) return false;

				str.Format(_T("Hello Time[s]: %u"), stpx->HelloTime>>8);
				aItem = theTree.InsertItem(str, cItem, TVI_LAST);
				if(aItem==NULL) return false;

				str.Format(_T("Forward Delay[s]: %u"), stpx->ForwardDelay>>8);
				aItem = theTree.InsertItem(str, cItem, TVI_LAST);
				if(aItem==NULL) return false;
			}
		}
	}

	if(expand)
		theTree.Expand(item, TVE_EXPAND);

	return true;
}

//---------------------------------------------------------------------------

bool DlgDetails::AddDTPInfo(MMachineInfo* mmi, HTREEITEM parentItem, bool expand)
{
	HTREEITEM   item;
	CString     str;
	int         i, cnt;
	MDTPPacket  *dtpx;
	bool        err;

	if(mmi==NULL) return false;
	cnt = mmi->GetDTPPackCount();
	if(cnt==0) return true;

	str = _T("DTP");
	item = theTree.InsertItem(str, parentItem, TVI_LAST);
	if(item==NULL) return false;

	err = false;
	for(i=0; i<cnt; i++){
		dtpx = mmi->GetDTPPack(i);
		if(dtpx!=NULL)
			if(!AddDTPPacket(dtpx, item, expand))
				err = true;
	}

	if(expand)
		theTree.Expand(item, TVE_EXPAND);

	return !err;
}

bool DlgDetails::AddDTPPacket(MDTPPacket* packIn, HTREEITEM parentItem, bool expand)
{
	HTREEITEM   item, cItem;
	CString     str;
	int         i, cnt;
	MTLVRecord *rec;
	bool        err;

	if(packIn==NULL) return true;

	// deviceID, portID, platform
	str.Format(_T("MAC %s"), mDTPDecoder.GetMacTypeValue(packIn));
	item = theTree.InsertItem(str, parentItem, TVI_LAST);
	if(item==NULL) return false;

	cnt = packIn->xValuesList.GetSize();
	if(cnt==0) return true;

	err = false;
	for(i=0; i<cnt && !err; i++){
		rec = packIn->xValuesList.GetByIdx(i);
		if(rec!=NULL){
			str.Format(_T("%s: %s"), mDTPDecoder.GetTypeName(rec->xType), mDTPDecoder.GetValueName(rec));
			cItem = theTree.InsertItem(str, item, TVI_LAST);
			if(cItem==NULL) err = true;
		}
	}

	return !err;
}

//---------------------------------------------------------------------------

bool DlgDetails::AddDnsNames(MMachineInfo* mmi, HTREEITEM parentItem, bool expand)
{
	HTREEITEM item;
	HTREEITEM cItem;
	CString str;
	int i, cnt;
	MDnsName *dnsName;

	if(mmi==NULL) return false;

	cnt = mmi->GetDnsNameCount();
	if(cnt<0) return false;
	if(cnt==0) return true;

	str = _T("DNS Names");
	item = theTree.InsertItem(str, parentItem, TVI_LAST);
	if(item==NULL) return false;

	for(i=0; i<cnt; i++){
		dnsName = mmi->GetDnsName(i);
		if(dnsName!=NULL){
			if(dnsName->nameDnsTTL!=0)
				str.Format(_T("%s: %s, TTL %s"), wd.GetDnsQueryTypeName(dnsName->nameType), dnsName->nameDns, DwTimeToDHMS(dnsName->nameDnsTTL));
			else
				str.Format(_T("%s: %s"), wd.GetDnsQueryTypeName(dnsName->nameType), dnsName->nameDns);
			cItem = theTree.InsertItem(str, item, TVI_LAST);
			if(cItem==NULL) return false;
		}
	}

	if(expand && item!=NULL)
		theTree.Expand(item, TVE_EXPAND);

	return true;
}

//---------------------------------------------------------------------------

bool DlgDetails::UpdateInfoDone(bool retValIn)
{
	theTree.SetRedraw(TRUE);
	return retValIn;
}

bool DlgDetails::UpdateInfo(MMachineInfo* mmi)
{
	HTREEITEM root;
	HTREEITEM item;
	CString str;
	CString sss;

	theTree.SetRedraw(FALSE);

	if(!theTree.DeleteAllItems())
		return UpdateInfoDone(false);

	if(mmi==NULL) return UpdateInfoDone(true);

	root = theTree.InsertItem(_T("Result"), TVI_ROOT, TVI_LAST);
	if(root==NULL) return UpdateInfoDone(false);

	// the IP address
	if(!mmi->address.addrIP.IsEmpty()){
		str.Format(_T("IP Address is %s"), mmi->address.addrIP.GetS());
		item = theTree.InsertItem(str, root, TVI_LAST);
		if(item==NULL) return UpdateInfoDone(false);
	}

	// the IPv6 address
	if(!mmi->address.addrIPv6.IsEmpty()){
		str.Format(_T("IPv6 Address is %s"), mmi->address.addrIPv6.GetS());
		item = theTree.InsertItem(str, root, TVI_LAST);
		if(item==NULL) return UpdateInfoDone(false);
	}

	// the MAC address
	if(!AddInfoMAC(mmi, root)) return UpdateInfoDone(false);

	if(!mmi->address.addrIPX.IsEmpty()){
		str.Format(_T("IPX Address is %s"), mmi->address.addrIPX.GetS());
		item = theTree.InsertItem(str, root, TVI_LAST);
		if(item==NULL) return UpdateInfoDone(false);
	}

	// Destination port if the scanning is in "Hunt Mode"
	if(!AddPortsForMethod(mmi, root, __wmtHunt, true)) return UpdateInfoDone(false);

	// Country code if it exists
	if(!mmi->countryCode.IsEmpty()){
		str.Format(_T("Country code: %s"), mmi->countryCode);
		item = theTree.InsertItem(str, root, TVI_LAST);
		if(item==NULL) return UpdateInfoDone(false);
	}

	// DNS names
	if(!AddDnsNames(mmi, root, true)) return UpdateInfoDone(false);

	// SSDP
	if(mmi->ssdp){
		str.Format(_T("SSDP broadcaster"));
		item = theTree.InsertItem(str, root, TVI_LAST);
		if(item==NULL) return UpdateInfoDone(false);
	}

	// stopped ?
	if(mmi->successfullyStopped){
		str.Format(_T("Stopped"));
		item = theTree.InsertItem(str, root, TVI_LAST);
		if(item==NULL) return UpdateInfoDone(false);
	}

	// NetBIOS informations
	if(!AddNetBiosNames(mmi, root, true))   return UpdateInfoDone(false);

	// Share informations
	if(!AddSharesInfo(mmi, root, false))     return UpdateInfoDone(false);

	// SNMP informations
	if(!AddSnmpSysInfo(mmi, root, true))    return UpdateInfoDone(false);

	// DHCP informations
	if(!AddInfoDHCP(mmi, root, true))       return UpdateInfoDone(false);

	// Promiscuous mode scan informations
	if(!AddPromiscResults(mmi, root, true)) return UpdateInfoDone(false);

	// IGMP Informations
	if(!AddIgmpInfo(mmi, root, true)) return UpdateInfoDone(false);

	// GxRP Informations
	if(!AddGxRPInfo(mmi, root, true)) return UpdateInfoDone(false);

	// CDP Informations
	if(!AddCDPInfo(mmi, root, true)) return UpdateInfoDone(false);

	// STP Informations
	if(!AddSTPInfo(mmi, root, true)) return UpdateInfoDone(false);

	// DTP Informations
	if(!AddDTPInfo(mmi, root, true)) return UpdateInfoDone(false);

	// the results of port scanning
	if(!AddPortsForMethod(mmi, root, __wmtSyn,          true))  return UpdateInfoDone(false);
	if(!AddPortsForMethod(mmi, root, __wmtFin,          false)) return UpdateInfoDone(false);
	if(!AddPortsForMethod(mmi, root, __wmtNull,         false)) return UpdateInfoDone(false);
	if(!AddPortsForMethod(mmi, root, __wmtXmas,         false)) return UpdateInfoDone(false);
	if(!AddPortsForMethod(mmi, root, __wmtUdpSend,      true))  return UpdateInfoDone(false);
	if(!AddPortsForMethod(mmi, root, __wmtIpProtocol,   false)) return UpdateInfoDone(false);

	if(!AddPortsForMethod(mmi, root, __wmt6Syn,         true))  return UpdateInfoDone(false);
	if(!AddPortsForMethod(mmi, root, __wmt6Fin,         false)) return UpdateInfoDone(false);
	if(!AddPortsForMethod(mmi, root, __wmt6Null,        false)) return UpdateInfoDone(false);
	if(!AddPortsForMethod(mmi, root, __wmt6Xmas,        false)) return UpdateInfoDone(false);
	if(!AddPortsForMethod(mmi, root, __wmt6UdpSend,     true))  return UpdateInfoDone(false);
	if(!AddPortsForMethod(mmi, root, __wmt6Proto,       false)) return UpdateInfoDone(false);

	if(!AddPortsForMethod(mmi, root, __wmtPassiveTCP,   true))  return UpdateInfoDone(false);
	if(!AddPortsForMethod(mmi, root, __wmtPassiveUDP,   true))  return UpdateInfoDone(false);
	if(!AddPortsForMethod(mmi, root, __wmtPassiveTCPv6, true))  return UpdateInfoDone(false);
	if(!AddPortsForMethod(mmi, root, __wmtPassiveUDPv6, true))  return UpdateInfoDone(false);

	if(!AddWmiInfo(&(mmi->wmiData), root, true)) return UpdateInfoDone(false);

	theTree.Expand(root, TVE_EXPAND);

	return UpdateInfoDone(true);
}

//---------------------------------------------------------------------------

bool DlgDetails::AddCounterTreeItem(HTREEITEM parentItemIn, CString nameIn, unsigned int valIn)
{
	HTREEITEM item;
	CString str;

	switch(valIn){
		case 0 :
			str.Format(_T("%s: -"), nameIn);
			break;

		case 1 :
			str.Format(_T("%s: 1 packet"), nameIn);
			break;

		default:
			str.Format(_T("%s: %d packets"), nameIn, valIn);
			break;
	}

	item = theTree.InsertItem(str, parentItemIn, TVI_LAST);

	return item==NULL ? false : true;
}

bool DlgDetails::AddTextItem(HTREEITEM parentItemIn, CString titleIn, CString valIn)
{
	CString str;
	HTREEITEM item;

	if(valIn.IsEmpty()) return true;

	if(titleIn.IsEmpty()) str = valIn;
	else                  str.Format(_T("%s %s"), titleIn, valIn);

	item = theTree.InsertItem(str, parentItemIn, TVI_LAST);

	return item==NULL ? false : true;
}

//---------------------------------------------------------------------------

bool DlgDetails::UpdateGlobalInfoDone(bool retValIn)
{
	theTree.SetRedraw(TRUE);
	return retValIn;
}

bool DlgDetails::UpdateGlobalInfo(MGlobalInfo* giIn)
{
	HTREEITEM root;
	HTREEITEM item;
	HTREEITEM sItem;
	MAddressIP aip;
	CString str;
	CString sss;

	theTree.SetRedraw(FALSE);

	if(!theTree.DeleteAllItems())
		return UpdateGlobalInfoDone(false);

	if(giIn==NULL)      return UpdateGlobalInfoDone(true);
	if(giIn->IsEmpty()) return UpdateGlobalInfoDone(true);

	root = theTree.InsertItem(_T("Global Info"), TVI_ROOT, TVI_LAST);
	if(root==NULL) return UpdateGlobalInfoDone(false);

	if(!giIn->ethernetCounters.IsEmpty()){
		// add ethernet counters

		item = theTree.InsertItem(_T("Ethernet Counters"), root, TVI_LAST);
		if(item==NULL) return UpdateGlobalInfoDone(false);

		if(!AddCounterTreeItem(item, _T("ARP"),          (unsigned int)giIn->ethernetCounters.cntARP)) return UpdateGlobalInfoDone(false);

		if(!AddCounterTreeItem(item, _T("IPv4 - TCP"),   (unsigned int)giIn->ethernetCounters.cntTCPv4))        return UpdateGlobalInfoDone(false);
		if(!AddCounterTreeItem(item, _T("IPv4 - UDP"),   (unsigned int)giIn->ethernetCounters.cntUDPv4))        return UpdateGlobalInfoDone(false);
		if(!AddCounterTreeItem(item, _T("IPv4 - ICMP"),  (unsigned int)giIn->ethernetCounters.cntICMPv4))       return UpdateGlobalInfoDone(false);
		if(!AddCounterTreeItem(item, _T("IPv4 - Other"), (unsigned int)giIn->ethernetCounters.cntIPv4Other))    return UpdateGlobalInfoDone(false);

		if(!AddCounterTreeItem(item, _T("IPv6 - TCP"),   (unsigned int)giIn->ethernetCounters.cntTCPv6))        return UpdateGlobalInfoDone(false);
		if(!AddCounterTreeItem(item, _T("IPv6 - UDP"),   (unsigned int)giIn->ethernetCounters.cntUDPv6))        return UpdateGlobalInfoDone(false);
		if(!AddCounterTreeItem(item, _T("IPv6 - ICMP"),  (unsigned int)giIn->ethernetCounters.cntICMPv6))       return UpdateGlobalInfoDone(false);
		if(!AddCounterTreeItem(item, _T("IPv6 - Other"), (unsigned int)giIn->ethernetCounters.cntIPv6Other))    return UpdateGlobalInfoDone(false);

		if(!AddCounterTreeItem(item, _T("Other"),        (unsigned int)giIn->ethernetCounters.cntEthOther))     return UpdateGlobalInfoDone(false);

		if(!AddCounterTreeItem(item, _T("TOTAL"),        (unsigned int)giIn->ethernetCounters.GetTotalCount())) return UpdateGlobalInfoDone(false);

		theTree.Expand(item, TVE_EXPAND);
	}

	if(!giIn->ntpIP.IsEmpty()){
		// add ntp info
		item = theTree.InsertItem(_T("NTP"), root, TVI_LAST);
		if(item==NULL) return UpdateGlobalInfoDone(false);

		str.Format(_T("NTP Server is at %s (%s)"), giIn->ntpIP.GetS(), giIn->ntpMAC.GetS());
		sItem = theTree.InsertItem(str, item, TVI_LAST);
		if(sItem==NULL) return UpdateGlobalInfoDone(false);

		// stratum
		sss = mNTPDecoder.GetStratumName(&(giIn->ntpMessage));
		if(!sss.IsEmpty()){
			str = sss;
			sItem = theTree.InsertItem(str, item, TVI_LAST);
			if(sItem==NULL) return UpdateGlobalInfoDone(false);
		}

		// poll interval
		sss = mNTPDecoder.GetPollingInterval(&(giIn->ntpMessage));
		if(!sss.IsEmpty()){
			str.Format(_T("Polling Interval: %s s"), sss);
			sItem = theTree.InsertItem(str, item, TVI_LAST);
			if(sItem==NULL) return UpdateGlobalInfoDone(false);
		}

		// precision
		sss = mNTPDecoder.GetPrecision(&(giIn->ntpMessage));
		if(!sss.IsEmpty()){
			str.Format(_T("Precision: %s s"), sss);
			sItem = theTree.InsertItem(str, item, TVI_LAST);
			if(sItem==NULL) return UpdateGlobalInfoDone(false);
		}

		// root delay
		sss = mNTPDecoder.GetRootDelay(&(giIn->ntpMessage));
		if(!sss.IsEmpty()){
			str.Format(_T("Root Delay: %s s"), sss);
			sItem = theTree.InsertItem(str, item, TVI_LAST);
			if(sItem==NULL) return UpdateGlobalInfoDone(false);
		}

		// root dispersion
		sss = mNTPDecoder.GetRootDispersion(&(giIn->ntpMessage));
		if(!sss.IsEmpty()){
			str.Format(_T("Root Dispersion: %s s"), sss);
			sItem = theTree.InsertItem(str, item, TVI_LAST);
			if(sItem==NULL) return UpdateGlobalInfoDone(false);
		}

		// reference timestamp
		sss = mNTPDecoder.GetReferenceTimestamp(&(giIn->ntpMessage));
		if(!sss.IsEmpty()){
			str.Format(_T("Reference Timestamp: %s"), sss);
			sItem = theTree.InsertItem(str, item, TVI_LAST);
			if(sItem==NULL) return UpdateGlobalInfoDone(false);
		}

		// originate timestamp
		sss = mNTPDecoder.GetOriginateTimestamp(&(giIn->ntpMessage));
		if(!sss.IsEmpty()){
			str.Format(_T("Originate Timestamp: %s"), sss);
			sItem = theTree.InsertItem(str, item, TVI_LAST);
			if(sItem==NULL) return UpdateGlobalInfoDone(false);
		}

		// receive timestamp
		sss = mNTPDecoder.GetReceiveTimestamp(&(giIn->ntpMessage));
		if(!sss.IsEmpty()){
			str.Format(_T("Receive Timestamp: %s"), sss);
			sItem = theTree.InsertItem(str, item, TVI_LAST);
			if(sItem==NULL) return UpdateGlobalInfoDone(false);
		}

		// transmit timestamp
		sss = mNTPDecoder.GetTransmitTimestamp(&(giIn->ntpMessage));
		if(!sss.IsEmpty()){
			str.Format(_T("Transmit Timestamp: %s"), sss);
			sItem = theTree.InsertItem(str, item, TVI_LAST);
			if(sItem==NULL) return UpdateGlobalInfoDone(false);
		}

		theTree.Expand(item, TVE_EXPAND);
	}

	theTree.Expand(root, TVE_EXPAND);

	return UpdateGlobalInfoDone(true);
}

//---------------------------------------------------------------------------

bool DlgDetails::AddWmiInfo(MWmiData* wmiDataIn, HTREEITEM parentItem, bool expand)
{
	bool found;
	bool res;
	HTREEITEM wmiNode, sNode;
	CString str;

	if(wmiDataIn==NULL) return false;

	found = false;
		if(!wmiDataIn->wmiCDROMDrive.IsEmpty())          found = true;
		if(!wmiDataIn->wmiDesktopMonitor.IsEmpty())      found = true;
		if(!wmiDataIn->wmiDiskDrive.IsEmpty())           found = true;
		if(!wmiDataIn->wmiDiskPartition.IsEmpty())       found = true;
		if(!wmiDataIn->wmiGroup.IsEmpty())               found = true;
		if(!wmiDataIn->wmiOperatingSystem.IsEmpty())     found = true;
		if(!wmiDataIn->wmiPhysicalMemory.IsEmpty())      found = true;
		if(!wmiDataIn->wmiProcessor.IsEmpty())           found = true;
		if(!wmiDataIn->wmiQuickFixEngineering.IsEmpty()) found = true;
		if(!wmiDataIn->wmiShare.IsEmpty())               found = true;
		if(!wmiDataIn->wmiUserAccount.IsEmpty())         found = true;
		if(!wmiDataIn->wmiVideoController.IsEmpty())     found = true;
		if(!wmiDataIn->wmiLoggedUser.IsEmpty())          found = true;
	if(!found) return true;

	str = _T("Windows Management Instrumentation");
	wmiNode = theTree.InsertItem(str, parentItem, TVI_LAST);
	if(wmiNode==NULL) return false;

	res = true;
	
	if(!wmiDataIn->wmiLoggedUser.IsEmpty()){
		str = _T("Logged User");
		sNode = theTree.InsertItem(str, wmiNode, TVI_LAST);
		if(sNode==NULL)
			res = false;
		else
			res &= AddWmiLoggedUser(&(wmiDataIn->wmiLoggedUser), sNode, expand);
	}

	if(!wmiDataIn->wmiOperatingSystem.IsEmpty()){
		str = _T("Operating System");
		sNode = theTree.InsertItem(str, wmiNode, TVI_LAST);
		if(sNode==NULL)
			res = false;
		else
			res &= AddWmiInfoOS(&(wmiDataIn->wmiOperatingSystem), sNode, expand);
	}

	qfeCnt = 0;
	if(!wmiDataIn->wmiQuickFixEngineering.IsEmpty()){
		str = _T("Quick Fix Engineering");
		sNode = theTree.InsertItem(str, wmiNode, TVI_LAST);
		if(sNode==NULL)
			res = false;
		else
			res &= AddWmiInfoQFE(&(wmiDataIn->wmiQuickFixEngineering), sNode, expand);

		if(qfeCnt>0){
			str.Format(_T("Quick Fix Engineering (%d)"), qfeCnt);
			theTree.SetItemText(sNode, str);
		}
	}

	if(!wmiDataIn->wmiShare.IsEmpty()){
		str = _T("Shares");
		sNode = theTree.InsertItem(str, wmiNode, TVI_LAST);
		if(sNode==NULL)
			res = false;
		else
			res &= AddWmiInfoShares(&(wmiDataIn->wmiShare), sNode, expand);
	}

	if(!wmiDataIn->wmiProcessor.IsEmpty()){
		str.Format(_T("Processor: %s"), GetFriendlyProcessorName(&(wmiDataIn->wmiProcessor)));
		sNode = theTree.InsertItem(str, wmiNode, TVI_LAST);
		if(sNode==NULL)
			res = false;
		else
			res &= AddWmiInfoProcessor(&(wmiDataIn->wmiProcessor), sNode, expand);
	}

	if(!wmiDataIn->wmiPhysicalMemory.IsEmpty()){
		str.Format(_T("Memory: %u MB"), (unsigned int)GetWmiInfoPhysicalMem(&(wmiDataIn->wmiPhysicalMemory)));
		sNode = theTree.InsertItem(str, wmiNode, TVI_LAST);
		if(sNode==NULL)
			res = false;
		else
			res &= AddWmiInfoPhysicalMem(&(wmiDataIn->wmiPhysicalMemory), sNode, expand);
	}

	if(!wmiDataIn->wmiDiskDrive.IsEmpty()){
		str = _T("Disk drive");
		sNode = theTree.InsertItem(str, wmiNode, TVI_LAST);
		if(sNode==NULL)
			res = false;
		else
			res &= AddWmiInfoDiskDrive(&(wmiDataIn->wmiDiskDrive), sNode, expand);
	}

	if(!wmiDataIn->wmiDiskPartition.IsEmpty()){
		str = _T("Disk partition");
		sNode = theTree.InsertItem(str, wmiNode, TVI_LAST);
		if(sNode==NULL)
			res = false;
		else
			res &= AddWmiInfoDiskPart(&(wmiDataIn->wmiDiskPartition), sNode, expand);
	}

	if(!wmiDataIn->wmiCDROMDrive.IsEmpty()){
		str = _T("CDROM drive");
		sNode = theTree.InsertItem(str, wmiNode, TVI_LAST);
		if(sNode==NULL)
			res = false;
		else
			res &= AddWmiInfoCDROM(&(wmiDataIn->wmiCDROMDrive), sNode, expand);
	}

	if(!wmiDataIn->wmiVideoController.IsEmpty()){
		str = _T("Video Controller");
		sNode = theTree.InsertItem(str, wmiNode, TVI_LAST);
		if(sNode==NULL)
			res = false;
		else
			res &= AddWmiInfoVideoController(&(wmiDataIn->wmiVideoController), sNode, expand);
	}

	if(!wmiDataIn->wmiDesktopMonitor.IsEmpty()){
		str = _T("Monitor");
		sNode = theTree.InsertItem(str, wmiNode, TVI_LAST);
		if(sNode==NULL)
			res = false;
		else
			res &= AddWmiInfoDesktopMonitor(&(wmiDataIn->wmiDesktopMonitor), sNode, expand);
	}

	usrCnt = 0;
	if(!wmiDataIn->wmiUserAccount.IsEmpty()){
		str = _T("User Accounts");
		sNode = theTree.InsertItem(str, wmiNode, TVI_LAST);
		if(sNode==NULL)
			res = false;
		else
			res &= AddWmiInfoUserAccount(&(wmiDataIn->wmiUserAccount), sNode, expand);

		if(usrCnt>0){
			str.Format(_T("User Accounts (%d)"), usrCnt);
			theTree.SetItemText(sNode, str);
		}
	}

	grpCnt = 0;
	if(!wmiDataIn->wmiGroup.IsEmpty()){
		str = _T("Groups");
		sNode = theTree.InsertItem(str, wmiNode, TVI_LAST);
		if(sNode==NULL)
			res = false;
		else
			res &= AddWmiInfoGroup(&(wmiDataIn->wmiGroup), sNode, expand);

		if(grpCnt>0){
			str.Format(_T("Groups (%d)"), grpCnt);
			theTree.SetItemText(sNode, str);
		}
	}

	if(expand)
		theTree.Expand(wmiNode, TVE_EXPAND);

	return res;
}

bool DlgDetails::AddWmiInfoOS(MWmi_Win32_OperatingSystem* dataIn, HTREEITEM parentItem, bool expand)
{
	CString str;

	if(dataIn==NULL) return false;

/*
	- CString        xBuildNumber;
	- unsigned int   xOSProductSuite;				// uint32==VT_I4==VARIANT.lVal		MWmiNames::GetOSProductSuiteName
	- unsigned short xOSType;						// uint16==VT_I4==VARIANT.lVal		MWmiNames::GetOSTypeName
*/

	if(!dataIn->xCaption.IsEmpty()){
		if(dataIn->xOtherTypeDescription.IsEmpty()) str.Format(_T("Name: %s"), dataIn->xCaption);
		else                                        str.Format(_T("Name: %s %s"), dataIn->xCaption, dataIn->xOtherTypeDescription);
		if(!AddTextItem(parentItem, _T(""), str)) return false;
	}

	if(dataIn->xServicePackMajorVersion!=0 || dataIn->xServicePackMinorVersion!=0){
		if(dataIn->xServicePackMinorVersion==0) str.Format(_T("Service Pack %d"), dataIn->xServicePackMajorVersion);
		else                                    str.Format(_T("Service Pack %d.%d"), dataIn->xServicePackMajorVersion, dataIn->xServicePackMinorVersion);
		if(!AddTextItem(parentItem, _T(""), str)) return false;
	}

	if(!AddTextItem(parentItem, _T("Version"),          dataIn->xVersion))        return false;
	if(!AddTextItem(parentItem, _T("Build Type:"),       dataIn->xBuildType))      return false;
	if(!AddTextItem(parentItem, _T("Serial Number:"),   dataIn->xSerialNumber))   return false;
	if(!AddTextItem(parentItem, _T("Organization:"),    dataIn->xOrganization))   return false;
	if(!AddTextItem(parentItem, _T("Registered User:"), dataIn->xRegisteredUser)) return false;

	if(dataIn->xProductType!=0)
		if(!AddTextItem(parentItem, _T("Type:"), wmiNames.GetProductTypeName(dataIn->xProductType))) return false;

	if(!AddTextItem(parentItem, _T("Install Date:"),      dataIn->xInstallDate))    return false;
	if(!AddTextItem(parentItem, _T("Last BootUp Time:"),   dataIn->xLastBootUpTime)) return false;

	if(!AddTextItem(parentItem, _T("Current Time Zone:"), wmiNames.GetTimeZone(dataIn->xCurrentTimeZone))) return false;

	if(!dataIn->xTotalVisibleMemorySize.IsEmpty()){
		str.Format(_T("Total Visible Memory: %d MB"), dataIn->GetSizeM_OS(dataIn->xTotalVisibleMemorySize));
		if(!AddTextItem(parentItem, _T(""), str)) return false;
	}
	
	if(!AddTextItem(parentItem, _T("Boot Device:"),       dataIn->xBootDevice))       return false;
	if(!AddTextItem(parentItem, _T("System Device:"),     dataIn->xSystemDevice))     return false;
	if(!AddTextItem(parentItem, _T("System Drive:"),      dataIn->xSystemDrive))      return false;
	if(!AddTextItem(parentItem, _T("System Directory:"),  dataIn->xSystemDirectory))  return false;
	if(!AddTextItem(parentItem, _T("Windows Directory:"), dataIn->xWindowsDirectory)) return false;
	if(!AddTextItem(parentItem, _T("Computer name:"),    dataIn->xCSName))           return false;

//	if(expand)
//		theTree.Expand(parentItem, TVE_EXPAND);

	return true;
}

bool DlgDetails::AddWmiInfoQFE(MWmi_Win32_QuickFixEngineering* dataIn, HTREEITEM parentItem, bool expand)
{
	MWmi_Win32_QuickFixEngineering* data;
	HTREEITEM sNode;
	CString str;
	bool wrongSetting;

	if(dataIn==NULL) return false;

	wrongSetting = false;
	data = dataIn;
	while(data!=NULL){
		qfeCnt++;
		str = data->xHotFixID;
		if(str.CompareNoCase(_T("File 1"))==0){
			if(!data->xServicePackInEffect.IsEmpty()){
				str = data->xServicePackInEffect;
				wrongSetting = true;
			}
		}
		sNode = theTree.InsertItem(str, parentItem, TVI_LAST);
		if(sNode==NULL) return false;

		if(!wrongSetting)
			if(!AddTextItem(sNode, _T("Service Pack"), data->xServicePackInEffect)) return false;

		if(!AddTextItem(sNode, _T("Description:"), data->xDescription)) return false;
		if(!AddTextItem(sNode, _T("Comments:"),    data->xFixComments)) return false;
		if(!AddTextItem(sNode, _T("Installed by"), data->xInstalledBy)) return false;
		if(!AddTextItem(sNode, _T("Installed on"), data->xInstalledOn)) return false;

		data = (MWmi_Win32_QuickFixEngineering*)data->next;
	}

//	if(expand)
//		theTree.Expand(parentItem, TVE_EXPAND);

	return true;
}

bool DlgDetails::AddWmiInfoShares(MWmi_Win32_Share* dataIn, HTREEITEM parentItem, bool expand)
{
	MWmi_Win32_Share* data;
	HTREEITEM sNode;
	CString str;

	if(dataIn==NULL) return false;

	data = dataIn;
	while(data!=NULL){
		str = data->xName;
		sNode = theTree.InsertItem(str, parentItem, TVI_LAST);
		if(sNode==NULL) return false;

		if(!AddTextItem(sNode, _T("Path:"), data->xPath)) return false;
		if(!AddTextItem(sNode, _T("Description:"), data->xDescription)) return false;
		if(!AddTextItem(sNode, _T("Type:"),        wmiNames.GetShareTypeName(data->xType))) return false;

		if(data->xAllowMaximum) str = _T("Maximum");
		else                    str.Format(_T("%d"), data->xMaximumAllowed);
		if(!AddTextItem(sNode, _T("Allowed count:"), str)) return false;

		data = (MWmi_Win32_Share*)data->next;
	}

	if(expand)
		theTree.Expand(parentItem, TVE_EXPAND);

	return true;
}

bool DlgDetails::AddWmiInfoDiskDrive(MWmi_Win32_DiskDrive* dataIn, HTREEITEM parentItem, bool expand)
{
	MWmi_Win32_DiskDrive* data;
	HTREEITEM sNode;
	CString str;

	if(dataIn==NULL) return false;

	data = dataIn;
	while(data!=NULL){
		str = data->xName;
		sNode = theTree.InsertItem(str, parentItem, TVI_LAST);
		if(sNode==NULL) return false;

		if(!AddTextItem(sNode, _T("Description:"), data->xDescription)) return false;
		if(!AddTextItem(sNode, _T("Manufacturer:"), data->xManufacturer)) return false;
		if(!AddTextItem(sNode, _T("Model:"), data->xModel)) return false;

		if(!data->xSize.IsEmpty())
			if(!AddTextItem(sNode, _T("Size:"), wmiNames.GetDiskSizeHuman(data->xSize))) return false;

		if(data->xPartitions!=0){
			str.Format(_T("%d"), data->xPartitions);
			if(!AddTextItem(sNode, _T("Partitions:"), str)) return false;
		}

		if(data->xSignature!=0){
			str.Format(_T("%d"), data->xSignature);
			if(!AddTextItem(sNode, _T("Signature:"), str)) return false;
		}

		data = (MWmi_Win32_DiskDrive*)data->next;
	}

	if(expand)
		theTree.Expand(parentItem, TVE_EXPAND);

	return true;
}

bool DlgDetails::AddWmiInfoDiskPart(MWmi_Win32_DiskPartition* dataIn, HTREEITEM parentItem, bool expand)
{
	MWmi_Win32_DiskPartition* data;
	HTREEITEM sNode;
	CString str;

	if(dataIn==NULL) return false;

	data = dataIn;
	while(data!=NULL){
		str = data->xName;
		sNode = theTree.InsertItem(str, parentItem, TVI_LAST);
		if(sNode==NULL) return false;

		if(!AddTextItem(sNode, _T("Description:"), data->xDescription)) return false;
		if(!AddTextItem(sNode, _T("Type:"), data->xType)) return false;

		if(!data->xSize.IsEmpty())
			if(!AddTextItem(sNode, _T("Size:"), wmiNames.GetDiskSizeHuman(data->xSize))) return false;

		if(!data->xStartingOffset.IsEmpty())
			if(!AddTextItem(sNode, _T("Starting offset:"), data->xStartingOffset)) return false;
		if(!data->xNumberOfBlocks.IsEmpty())
			if(!AddTextItem(sNode, _T("Number of blocks:"), data->xNumberOfBlocks)) return false;

		if(data->xPrimaryPartition)
			if(!AddTextItem(sNode, _T("Primary partition:"), _T("true"))) return false;
		if(data->xBootable)
			if(!AddTextItem(sNode, _T("Bootable:"), _T("true"))) return false;
		if(data->xBootPartition)
			if(!AddTextItem(sNode, _T("Boot partition:"), _T("true"))) return false;

		data = (MWmi_Win32_DiskPartition*)data->next;
	}

	if(expand)
		theTree.Expand(parentItem, TVE_EXPAND);

	return true;
}

bool DlgDetails::AddWmiInfoProcessor(MWmi_Win32_Processor* dataIn, HTREEITEM parentItem, bool expand)
{
	MWmi_Win32_Processor* data;
	HTREEITEM sNode;
	CString str;

/*
	unsigned short xAddressWidth;
	unsigned short xCurrentVoltage;
	unsigned short xDataWidth;
	unsigned short xLevel;
	unsigned short xLoadPercentage;
	unsigned short xRevision;
	CString        xStepping;
	CString        xVersion;
*/

	if(dataIn==NULL) return false;

	data = dataIn;
	while(data!=NULL){
		str = data->xName.Trim();
		sNode = theTree.InsertItem(str, parentItem, TVI_LAST);
		if(sNode==NULL) return false;

		if(!AddTextItem(sNode, _T("Manufacturer:"), data->xManufacturer)) return false;
		if(!AddTextItem(sNode, _T("Description:"), data->xDescription)) return false;
		if(!AddTextItem(sNode, _T("Processor ID:"), data->xProcessorId)) return false;
		if(!AddTextItem(sNode, _T("Device ID:"), data->xDeviceID)) return false;

		if(data->xMaxClockSpeed!=0){
			str.Format(_T("%d"), data->xMaxClockSpeed);
			if(!AddTextItem(sNode, _T("Clock speed:"), str)) return false;
		}
		if(data->xCurrentClockSpeed!=0){
			str.Format(_T("%d"), data->xCurrentClockSpeed);
			if(!AddTextItem(sNode, _T("Current clock speed:"), str)) return false;
		}
		if(data->xExtClock!=0){
			str.Format(_T("%d"), data->xExtClock);
			if(!AddTextItem(sNode, _T("External clock speed:"), str)) return false;
		}

		if(data->xArchitecture!=0)
			if(!AddTextItem(sNode, _T("Architecture:"), wmiNames.GetArchitectureName(data->xArchitecture))) return false;

		if(data->xFamily!=0){
			if(data->xFamily==1)
				if(!AddTextItem(sNode, _T("Family:"), data->xOtherFamilyDescription)) return false;
			else
				if(!AddTextItem(sNode, _T("Family:"), wmiNames.GetFamilyName(data->xFamily))) return false;
		}

		if(data->xProcessorType!=0)
			if(!AddTextItem(sNode, _T("Family:"), wmiNames.GetProcessorTypeName(data->xProcessorType))) return false;

		if(data->xVoltageCaps!=0)
			if(!AddTextItem(sNode, _T("Voltage caps.:"), wmiNames.GetVoltageCapsName(data->xVoltageCaps))) return false;
		
		if(data->xCpuStatus!=0)
			if(!AddTextItem(sNode, _T("Status:"), wmiNames.GetCpuStatusName(data->xCpuStatus))) return false;

		data = (MWmi_Win32_Processor*)data->next;
	}

	if(expand)
		theTree.Expand(parentItem, TVE_EXPAND);

	return true;
}

CString DlgDetails::GetFriendlyProcessorName(MWmi_Win32_Processor* dataIn)
{
	CString str;

	if(dataIn==NULL){
		str = _T("-");
	}
	else{
		if(dataIn->xCurrentClockSpeed!=0)
			str.Format(_T("%s, %d MHz"), dataIn->xName.Trim(), dataIn->xCurrentClockSpeed);
		else
			str = dataIn->xName.Trim();
	}

	return str;
}

bool DlgDetails::AddWmiInfoPhysicalMem(MWmi_Win32_PhysicalMemory* dataIn, HTREEITEM parentItem, bool expand)
{
	MWmi_Win32_PhysicalMemory* data;
	HTREEITEM sNode;
	CString str;

	if(dataIn==NULL) return false;

	data = dataIn;
	while(data!=NULL){
		str = data->xName;
		sNode = theTree.InsertItem(str, parentItem, TVI_LAST);
		if(sNode==NULL) return false;

		if(!AddTextItem(sNode, _T("Description:"), data->xDescription)) return false;
		if(!AddTextItem(sNode, _T("Size:"), wmiNames.GetMemSizeHuman(data->xCapacity))) return false;

		if(data->xSpeed!=0){
			str.Format(_T("%d"), data->xSpeed);
			if(!AddTextItem(sNode, _T("Speed [ns]:"), str)) return false;
		}

		if(!AddTextItem(sNode, _T("Location:"), data->xDeviceLocator)) return false;
		if(!AddTextItem(sNode, _T("Tag:"), data->xTag)) return false;

		if(data->xMemoryType!=0)
			if(!AddTextItem(sNode, _T("Memory type:"), wmiNames.GetMemoryTypeName(data->xMemoryType))) return false;
		if(data->xTypeDetail!=0)
			if(!AddTextItem(sNode, _T("Type detail:"), wmiNames.GetTypeDetailName(data->xTypeDetail))) return false;
		if(data->xFormFactor!=0)
			if(!AddTextItem(sNode, _T("Form factor:"), wmiNames.GetFormFactorName(data->xFormFactor))) return false;

		if(data->xDataWidth!=0){
			str.Format(_T("%d"), data->xDataWidth);
			if(!AddTextItem(sNode, _T("Data width [bits]:"), str)) return false;
		}
		if(data->xTotalWidth!=0){
			str.Format(_T("%d"), data->xTotalWidth);
			if(!AddTextItem(sNode, _T("Total width [bits]:"), str)) return false;
		}

		data = (MWmi_Win32_PhysicalMemory*)data->next;
	}

	if(expand)
		theTree.Expand(parentItem, TVE_EXPAND);

	return true;
}

unsigned __int64 DlgDetails::GetWmiInfoPhysicalMem(MWmi_Win32_PhysicalMemory* dataIn)
{
	MWmi_Win32_PhysicalMemory* data;
	unsigned __int64 memSize;

	if(dataIn==NULL) return false;

	data = dataIn;
	memSize = 0;
	while(data!=NULL){
		memSize += wmiNames.GetMemSizeInt(data->xCapacity);
		data = (MWmi_Win32_PhysicalMemory*)data->next;
	}

	return memSize;
}

bool DlgDetails::AddWmiInfoCDROM(MWmi_Win32_CDROMDrive* dataIn, HTREEITEM parentItem, bool expand)
{
	MWmi_Win32_CDROMDrive* data;
	HTREEITEM sNode;
	CString str;

	if(dataIn==NULL) return false;

	data = dataIn;
	while(data!=NULL){
		str = data->xName;
		sNode = theTree.InsertItem(str, parentItem, TVI_LAST);
		if(sNode==NULL) return false;

		if(!AddTextItem(sNode, _T("Manufacturer:"), data->xManufacturer)) return false;
		if(!AddTextItem(sNode, _T("Description:"),  data->xDescription)) return false;
		if(!AddTextItem(sNode, _T("Drive:"),        data->xDrive)) return false;
		if(!AddTextItem(sNode, _T("Media Type:"),    data->xMediaType)) return false;
		if(data->xMediaLoaded){
			if(!AddTextItem(sNode, _T("Volume Name:"),         data->xVolumeName)) return false;
			if(!AddTextItem(sNode, _T("Size:"),               data->xSize)) return false;
			if(!AddTextItem(sNode, _T("Volume Serial Number:"), data->xVolumeSerialNumber)) return false;
		}
		else{
			if(!AddTextItem(sNode, _T(""), _T("No media loaded"))) return false;
		}

		data = (MWmi_Win32_CDROMDrive*)data->next;
	}

	if(expand)
		theTree.Expand(parentItem, TVE_EXPAND);

	return true;
}

bool DlgDetails::AddWmiInfoVideoController(MWmi_Win32_VideoController* dataIn, HTREEITEM parentItem, bool expand)
{
	MWmi_Win32_VideoController* data;
	HTREEITEM sNode;
	CString str;

	if(dataIn==NULL) return false;

	data = dataIn;
	while(data!=NULL){
		str = data->xName;
		sNode = theTree.InsertItem(str, parentItem, TVI_LAST);
		if(sNode==NULL) return false;

		if(!AddTextItem(sNode, _T("Description:"), data->xDescription)) return false;
		if(!AddTextItem(sNode, _T("Video Processor:"), data->xVideoProcessor)) return false;
		if(data->xAdapterRAM!=0){
			str.Format(_T("%d MB"), data->xAdapterRAM/1048576);
			if(!AddTextItem(sNode, _T("Adapter RAM:"), str)) return false;
		}
		if(data->xCurrentHorizontalResolution!=0){
			str.Format(_T("%d x %d, %d bpp"), data->xCurrentHorizontalResolution, data->xCurrentVerticalResolution, data->xCurrentBitsPerPixel);
			if(!AddTextItem(sNode, _T("Current resolution:"), str)) return false;
		}
		if(data->xCurrentRefreshRate!=0){
			str.Format(_T("%d Hz"), data->xCurrentRefreshRate);
			if(!AddTextItem(sNode, _T("Current refresh rate:"), str)) return false;
		}

		if(!AddTextItem(sNode, _T("Installed display drivers:"), data->xInstalledDisplayDrivers)) return false;
		if(!AddTextItem(sNode, _T("Driver version:"),            data->xDriverVersion))           return false;
		if(!AddTextItem(sNode, _T("Driver date:"),               data->xDriverDate))              return false;
		if(!AddTextItem(sNode, _T("Inf filename:"),              data->xInfFilename))             return false;
		if(!AddTextItem(sNode, _T("Inf section:"),               data->xInfSection))              return false;

		data = (MWmi_Win32_VideoController*)data->next;
	}

	if(expand)
		theTree.Expand(parentItem, TVE_EXPAND);

	return true;
}

bool DlgDetails::AddWmiInfoDesktopMonitor(MWmi_Win32_DesktopMonitor* dataIn, HTREEITEM parentItem, bool expand)
{
	MWmi_Win32_DesktopMonitor* data;
	HTREEITEM sNode;
	CString str;

	if(dataIn==NULL) return false;

	data = dataIn;
	while(data!=NULL){
		str = data->xName;
		sNode = theTree.InsertItem(str, parentItem, TVI_LAST);
		if(sNode==NULL) return false;

		if(!AddTextItem(sNode, _T("Manufacturer:"), data->xMonitorManufacturer)) return false;
		if(!AddTextItem(sNode, _T("Type:"), data->xMonitorType)) return false;
		if(!AddTextItem(sNode, _T("Description:"), data->xDescription)) return false;

		if(data->xScreenWidth!=0){
			str.Format(_T("%d x %d"), data->xScreenWidth, data->xScreenHeight);
			if(!AddTextItem(sNode, _T("Resolution:"), str)) return false;
		}
		if(data->xPixelsPerXLogicalInch!=0){
			str.Format(_T("%d x %d"), data->xPixelsPerXLogicalInch, data->xPixelsPerYLogicalInch);
			if(!AddTextItem(sNode, _T("Pixels per logical inch:"), str)) return false;
		}

		data = (MWmi_Win32_DesktopMonitor*)data->next;
	}

	if(expand)
		theTree.Expand(parentItem, TVE_EXPAND);

	return true;
}

bool DlgDetails::AddWmiInfoUserAccount(MWmi_Win32_UserAccount* dataIn, HTREEITEM parentItem, bool expand)
{
	MWmi_Win32_UserAccount* data;
	HTREEITEM sNode;
	CString str;

	if(dataIn==NULL) return false;

	data = dataIn;
	while(data!=NULL){
		str = data->xName;
		if(data->xDisabled)
			str += _T(" (Disabled)");
		if(data->xLockout)
			str += _T(" (Account locked out)");
		sNode = theTree.InsertItem(str, parentItem, TVI_LAST);
		if(sNode==NULL) return false;

		if(!AddTextItem(sNode, _T("Description:"), data->xDescription)) return false;
		if(!AddTextItem(sNode, _T("Domain:"), data->xDomain)) return false;
		if(!AddTextItem(sNode, _T("Full name:"), data->xFullName)) return false;
		if(!AddTextItem(sNode, _T("SID:"), data->xSID)) return false;

		if(!data->xSIDType!=0)
			if(!AddTextItem(sNode, _T("SID Type:"), wmiNames.GetSIDTypeName(data->xSIDType))) return false;

		if(!AddTextItem(sNode, _T("Account Type:"), wmiNames.GetAccountTypeName(data->xAccountType))) return false;

		if(data->xLocalAccount)
			if(!AddTextItem(sNode, _T(""), _T("Local account"))) return false;

		if(!AddTextItem(sNode, _T("Password changeable:"), data->xPasswordChangeable ? _T("true") : _T("false"))) return false;
		if(!AddTextItem(sNode, _T("Password expires:"), data->xPasswordExpires ? _T("true") : _T("false"))) return false;
		if(!AddTextItem(sNode, _T("Password required:"), data->xPasswordRequired ? _T("true") : _T("false"))) return false;

		if(!AddTextItem(sNode, _T("Status:"), data->xStatus)) return false;

		data = (MWmi_Win32_UserAccount*)data->next;

		usrCnt++;
	}

	if(expand)
		theTree.Expand(parentItem, TVE_EXPAND);

	return true;
}

bool DlgDetails::AddWmiInfoGroup(MWmi_Win32_Group* dataIn, HTREEITEM parentItem, bool expand)
{
	MWmi_Win32_Group* data;
	HTREEITEM sNode;
	CString str;

	if(dataIn==NULL) return false;

	data = dataIn;
	while(data!=NULL){
		str = data->xName;
		sNode = theTree.InsertItem(str, parentItem, TVI_LAST);
		if(sNode==NULL) return false;

		if(!AddTextItem(sNode, _T("Description:"), data->xDescription)) return false;
		if(!AddTextItem(sNode, _T("Domain:"), data->xDomain)) return false;
		if(!AddTextItem(sNode, _T("SID:"), data->xSID)) return false;

		if(!data->xSIDType!=0)
			if(!AddTextItem(sNode, _T("SID Type:"), wmiNames.GetSIDTypeName(data->xSIDType))) return false;

		if(data->xLocalAccount)
			if(!AddTextItem(sNode, _T(""), _T("Local account"))) return false;

		if(!AddTextItem(sNode, _T("Status:"), data->xStatus)) return false;

		data = (MWmi_Win32_Group*)data->next;

		grpCnt++;
	}

	if(expand)
		theTree.Expand(parentItem, TVE_EXPAND);

	return true;
}

bool DlgDetails::AddWmiLoggedUser(MWmi_Win32_LoggedUser* dataIn, HTREEITEM parentItem, bool expand)
{
	MWmi_Win32_LoggedUser* data;
	HTREEITEM sNode;
	CString str;

	if(dataIn==NULL) return false;

	data = dataIn;
	while(data!=NULL){
		str = data->xLoggedUser;
		sNode = theTree.InsertItem(str, parentItem, TVI_LAST);
		if(sNode==NULL) return false;

		data = (MWmi_Win32_LoggedUser*)data->next;
	}

	if(expand)
		theTree.Expand(parentItem, TVE_EXPAND);

	return true;
}

//---------------------------------------------------------------------------

void DlgDetails::OnOK()
{
	// CRgnDialog::OnOK();
}

void DlgDetails::OnCancel()
{
	// CRgnDialog::OnCancel();
}

//---------------------------------------------------------------------------
